# 1.
# 创建一个BankAccount类，要求：
# 有类属性bank_name（银行名称）
# 有实例属性account_name（账户名）和balance（余额）
# 有方法deposit(amount)（存款）和withdraw(amount)（取款）
# 有方法display()显示账户信息
# 修改上面的BankAccount类，将实例属性私有化，
#    并提供相应的getter和setter方法，
#    在setter方法中加入验证逻辑（余额不能为负数）。
# 为BankAccount类添加一个类方法
#    change_bank_name(new_name)
#    用于修改银行名称，
#    和一个静态方法
#    calculate_interest(principal, rate, time)
#    用于计算利息(金额，利率，时间)。
#
class BankAccount:
    bank_name = "中国银行"  # 类属性

    def __init__(self, account_name, balance=0.0):
        self.__account_name = account_name  # 私有属性
        self.set_balance(balance)  # 使用setter方法设置初始余额

    # account_name 的 getter 方法
    def get_account_name(self):
        return self.__account_name

    # account_name 的 setter 方法
    def set_account_name(self, account_name):
        self.__account_name = account_name

    # balance 的 getter 方法
    def get_balance(self):
        return self.__balance

    # balance 的 setter 方法，包含验证逻辑
    def set_balance(self, balance):
        if balance < 0:
            print("余额不能为负数")
        self.__balance = balance

    # 存款方法
    def deposit(self, amount):
        if amount <= 0:
            print("存款金额必须为正数")
        self.set_balance(self.get_balance() + amount)
        print(f"成功存款 {amount} 元")

    # 取款方法
    def withdraw(self, amount):
        if amount <= 0:
            print("取款金额必须为正数")
        if amount > self.get_balance():
            print("余额不足")
        self.set_balance(self.get_balance() - amount)
        print(f"成功取款 {amount} 元")

    # 显示账户信息
    def display(self):
        print(f"银行: {self.bank_name}")
        print(f"账户名: {self.get_account_name()}")
        print(f"余额: {self.get_balance()} 元")

    # 类方法：修改银行名称
    @classmethod
    def change_bank_name(cls, new_name):
        cls.bank_name = new_name
        print(f"银行名称已更改为: {new_name}")

    # 静态方法：计算利息
    @staticmethod
    def calculate_interest(principal, rate, time):
        """
        计算利息
        principal: 本金
        rate: 利率（年利率）
        time: 时间（年）
        利息金额
        """
        if principal < 0 or rate < 0 or time < 0:
            print("参数不能为负数")
        interest = principal * rate * time
        print(f"本金 {principal} 元，利率 {rate*100}%，时间 {time} 年，利息为: {interest} 元")
        return interest
# 创建账户
account = BankAccount("张三", 1000)
print("=== 初始账户信息 ===")
account.display()
print()

# 存款
print("=== 存款操作 ===")
account.deposit(500)
account.display()
print()

# 取款
print("=== 取款操作 ===")
account.withdraw(200)
account.display()
print()

# 修改银行名称
print("=== 修改银行名称 ===")
BankAccount.change_bank_name("中国工商银行")
account.display()
print()

# 计算利息
print("=== 计算利息 ===")
interest = BankAccount.calculate_interest(10000, 0.05, 2)
print()

# 尝试设置负数余额（会抛出异常）
print("=== 尝试设置负数余额 ===")
try:
    account.set_balance(-100)
except ValueError as e:
    print(f"错误: {e}")
# 2.
# 创建一个Animal类，实现以下魔术方法：
# __init__：初始化动物名称和年龄
# __str__：返回动物的描述信息
# __del__：在对象销毁时打印信息
class Animal:
    Animaltype = "猫"

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"{self.name}的品种为{Animal.Animaltype},年龄为{self.age}"

    def __del__(self):
        print("---对象被销毁时，执行该方法---")

ahuang = Animal("阿黄",2)
print(ahuang) # <__main__.Dog object at 0x0000027498BD27B0>
# 打印对象，默认结果为对象的类型和内存地址 不同对象的内存地址不同
bai = ahuang
hei = Animal("小黑",2)
print(hei)
print(bai)
#
# 3）class Book:
#     def __init__(self, title, price):
#         self.title = title
#         self.price = price
#     # 请在此处添加 __str__ 方法
#
# # 测试代码
# book = Book("Python入门", 59.8)
# print(book) # 期望输出: 书名: 《Python入门》, 价格: 59.8元
class Book:
    def __init__(self, title, price):
        self.title = title
        self.price = price

    def __str__(self):
        return f"书名:《{self.title}》,价格:{self.price}"

book = Book("Python入门", 59.8)
print(book)
# 4）请设计一个Rectangle(矩形)类。
#   属性:私有属性__length(长),__width(宽)。
#   方法:__init__(self, length, width):初始化长和宽。
#       set_length(self,length)和 get_length(self):
#          设置和获取长度,设置时需检查长度是否大于0。
#       set_width(self,width)和 get_width(self):
#          设置和获取宽度,设置时需检查宽度是否大于0。
#       get_area(self):计算并返回矩形的面积。
#       get_perimeter(self):计算并返回矩形的周长。
#       __str__(self):返回矩形的描述信息,
#          如“矩形[长=5.0,宽=3.0]”。
# 编写代码测试这个类,创建一个矩形对象,
# 计算其面积和周长,并尝试设置一个非法的负值宽度。
#
class Rectangle:
    def __init__(self, length, width):
        self.set_length(length)  # 使用setter方法设置初始长度
        self.set_width(width)    # 使用setter方法设置初始宽度

    # 设置和获取长度
    def set_length(self, length):
        if length <= 0:
            raise ValueError("长度必须大于0")
        self.__length = length

    def get_length(self):
        return self.__length

    # 设置和获取宽度
    def set_width(self, width):
        if width <= 0:
            # raise ValueError("宽度必须大于0")
            print("宽度必须大于0")
        self.__width = width

    def get_width(self):
        return self.__width

    # 计算并返回矩形的面积
    def get_area(self):
        return self.__length * self.__width

    # 计算并返回矩形的周长
    def get_perimeter(self):
        return 2 * (self.__length + self.__width)

    # 返回矩形的描述信息
    def __str__(self):
        return f"矩形[长={self.__length}, 宽={self.__width}]"

# 创建一个矩形对象
try:
    rect = Rectangle(5.0, 3.0)
    print("矩形创建成功")
    print(rect)

    # 计算面积和周长
    print(f"面积: {rect.get_area()}")
    print(f"周长: {rect.get_perimeter()}")

    # 修改长度和宽度
    rect.set_length(7.5)
    rect.set_width(4.2)
    print(f"修改后的{rect}")
    print(f"新面积: {rect.get_area()}")
    print(f"新周长: {rect.get_perimeter()}")

    # 尝试设置一个非法的负值宽度
    print("\n尝试设置负值宽度...")
    rect.set_width(-2.0)

except ValueError as e:
    print(f"错误: {e}")

# 测试获取方法
print(f"\n当前长度: {rect.get_length()}")
print(f"当前宽度: {rect.get_width()}")
# 5.总结并手写：
# 什么是面向对象编程？它与面向过程编程的主要区别是什么？
# 解释类和对象的关系，并举例说明。
# Python中self关键字的作用是什么？
# __init__()有什么特殊之处？它什么时候被调用？
# 什么是封装